package com.trans.utils;


import com.trans.asserts.Assert;
import com.trans.auxiliary.Params;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;

/**
 * 获取所有字段
 *
 *
 * @Author xwduo
 * @Date 2023-03-27 15:44
 */
public class ParamsUtils {

    private static final String GET = "get";
    private static final String IS = "is";

    private static final Map<Class,Map<String,Params>> PARAMS_CACHE = new HashMap<>();

    public static List<Params> getAllPossibilityFields(Object object){
        Class<?> clazz = object.getClass();
        if(PARAMS_CACHE.containsKey(clazz)){
            return new ArrayList<>(PARAMS_CACHE.get(clazz).values());
        }
        Map<String,Method> methodMap = new HashMap<>();
        Map<String,Params> fieldMap = new HashMap<>();
        while (clazz != null ){
            Method[] methods = clazz.getDeclaredMethods();
            for (Method method : methods) {
                //如果是本地方法，则继续循环
                if(Modifier.isNative(method.getModifiers())){
                    continue;
                }
                //优先循环对象方法
                if(method.getParameterCount() == 0){
                    if(method.getName().startsWith(GET) && method.getReturnType() != Boolean.class){
                        markMethod(method,GET,methodMap);
                    }
                    if(method.getName().startsWith(IS) && method.getReturnType()== Boolean.class){
                        markMethod(method,IS,methodMap);
                    }
                }
            }
            Field[] declaredFields = clazz.getDeclaredFields();
            for (Field declaredField : declaredFields) {
                Params params;
                String fieldName = declaredField.getName();
                //字段已存在就不管了，以子类为主
                if(! fieldMap.containsKey(fieldName)){
                    if(methodMap.containsKey(fieldName)){
                        Method method = methodMap.get(fieldName);
                        params = new Params(method,declaredField , fieldName);
                        methodMap.remove(fieldName);
                    }else {
                        params = new Params(declaredField);
                    }
                    fieldMap.put(fieldName,params);
                }

            }
            for (Map.Entry<String, Method> methodEntry : methodMap.entrySet()) {
                String realName = methodEntry.getKey();
                if(!fieldMap.containsKey(realName)){
                    //字段已存在就不管了，以子类为主
                    fieldMap.put(realName,new Params(methodEntry.getValue(), realName));
                }
            }
            clazz = clazz.getSuperclass();
        }
        List<Params> params = new ArrayList<>(fieldMap.values());
        PARAMS_CACHE.put(clazz,fieldMap);
        return params;
    }

    private static void markMethod(Method method, String prefix ,Map<String,Method> methodMap){
        String name = method.getName();
        String realName = name.substring(prefix.length());
        realName = StringUtils.lowerFirst(realName);
        methodMap.put(realName,method);
    }


    public static Object getObjVal(Object obj , String name){
        Class<?> clazz = obj.getClass();
        if( ! PARAMS_CACHE.containsKey(clazz) ){
            getAllPossibilityFields(obj);
        }
        Map<String, Params> paramsMap = PARAMS_CACHE.get(clazz);
        if(null != paramsMap){
            Params params = paramsMap.get(name);
            if(null != params){
                return params.findObjectVal(obj);
            }
        }
        return null;
    }
}
